package com.smartao.core.orm.mybatis;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeException;
import org.apache.ibatis.type.TypeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smartao.core.orm.entity.BaseEntity;

/**
 * Mybatis实体类的{@link TypeHandler}
 * @author Ricky
 * @param <T>
 */
public abstract class EntityTypeHandler<T extends BaseEntity<T>> implements TypeHandler<T> {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
		if (parameter == null) {
			if (jdbcType == null) {
				throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
			}
			try {
				ps.setNull(i, jdbcType.TYPE_CODE);
			} catch (SQLException e) {
				throw new TypeException("Error setting null for parameter #" + i	+ " with JdbcType "	+ jdbcType + " . "
								+ "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
								+ "Cause: " + e, e);
			}
		} else {
			setNonNullParameter(ps, i, parameter, jdbcType);
		}
	}

	@Override
	public T getResult(ResultSet rs, String columnName) throws SQLException {
		T result = getNullableResult(rs, columnName);
		if (rs.wasNull()) {
			return null;
		} else {
			return result;
		}
	}

	@Override
	public T getResult(ResultSet rs, int columnIndex) throws SQLException {
		T result = getNullableResult(rs, columnIndex);
		if (rs.wasNull()) {
			return null;
		} else {
			return result;
		}
	}

	@Override
	public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
		T result = getNullableResult(cs, columnIndex);
		if (cs.wasNull()) {
			return null;
		} else {
			return result;
		}
	}
	
	protected void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)
			throws SQLException {
		ps.setLong(i, parameter.getId());
	}

	protected T getNullableResult(ResultSet rs, String columnName) throws SQLException {
		Long id = rs.getLong(columnName);
		return getEntityInstance(id);
	}

	protected T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		Long id = rs.getLong(columnIndex);
		return getEntityInstance(id);
	}

	protected T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		Long id = cs.getLong(columnIndex);
		return getEntityInstance(id);
	}
	
	protected T getEntityInstance(Long id){
		Class<T> type = getEntityClass();
		return getEntityInstance(id,type);
	}

	protected T getEntityInstance(Long id, Class<T> type){
		try {
			T entity = type.newInstance();
			entity.setId(id);
			return entity;
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
	}
	
	/**
	 * 获取泛型类型(为实体类)
	 * @return
	 */
	public abstract Class<T> getEntityClass();
}
